// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020, LomboTech Co.Ltd.
 * Author: lomboswer <lomboswer@lombotech.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/consumer.h>

static struct regulator *vdd_cpu;
static struct regulator *vdd_ax;
static struct regulator *vcc_dram;
static struct regulator *vdd_gpu;
static struct regulator *vdd_sys;
static struct regulator *vcc_io;
static struct regulator *vcc_pa;
static struct regulator *vcc_qemmc;
static struct regulator *vcc_pll;
static struct regulator *vcc_ac;
static struct regulator *vcc_ddrpll;
static struct regulator *vpp_ddr4;
static struct regulator *vcc_lpddr;
static struct regulator *vcc_camio;
static struct regulator *vcc_amu;
static struct regulator *vdd_amu;

void regulator_test(void)
{
	int ret;
	int ve;
	int nv;
	int i;

	ret = regulator_enable(vdd_cpu);
	if (ret != 0) {
		pr_err("%s: %d, enable regulator vdd-cpu error\n",
			__func__, __LINE__);
		return;
	}

	nv = regulator_count_voltages(vdd_cpu);
	if (nv < 0) {
		pr_err("%s: %d, get count voltages for vdd-cpu error\n",
			__func__, __LINE__);
		return;
	}

	for (i = 0; i < nv; ++i) {

		ve = regulator_list_voltage(vdd_cpu, i);
		if (ve < 0) {
			pr_err("%s: %d, get voltags for position(%d) error\n",
				__func__, __LINE__, i);
			return;
		}

		ret = regulator_set_voltage(vdd_cpu, ve, ve);
		if (ret < 0) {
			pr_err("%s: %d, set voltage for vdd-cpu error\n",
				__func__, __LINE__);
			return;
		}

		ret = regulator_get_voltage(vdd_cpu);
		if (ret < 0) {
			pr_err("%s: %d, get voltage for vdd-cpu error\n",
				__func__, __LINE__);
			return;
		}

		if (ret != ve) {
			pr_err("%s: %d, set voltage for vdd-cpu error\n",
				__func__, __LINE__);
			return;
		}
	}
}

static const struct of_device_id test_dt_ids[] = {
	{ .compatible = "lombo-regulator-test", },
	{}
};
MODULE_DEVICE_TABLE(of, test_dt_ids);

static int regulator_test_probe(struct platform_device *pdev)
{
	int ret;

	vdd_cpu = devm_regulator_get(&pdev->dev, "vdd-cpu");
	if (IS_ERR(vdd_cpu)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vdd_cpu);
		return ret;
	}

	vdd_ax = devm_regulator_get(&pdev->dev, "vdd-ax");
	if (IS_ERR(vdd_ax)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vdd_ax);
		return ret;
	}

	vcc_dram = devm_regulator_get(&pdev->dev, "vcc-dram");
	if (IS_ERR(vcc_dram)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_dram);
		return ret;
	}

	vdd_gpu = devm_regulator_get(&pdev->dev, "vdd-gpu");
	if (IS_ERR(vdd_gpu)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vdd_gpu);
		return ret;
	}

	vdd_sys = devm_regulator_get(&pdev->dev, "vdd-sys");
	if (IS_ERR(vdd_sys)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vdd_sys);
		return ret;
	}

	vcc_io = devm_regulator_get(&pdev->dev, "vcc-io");
	if (IS_ERR(vcc_io)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_io);
		return ret;
	}

	vcc_pa = devm_regulator_get(&pdev->dev, "vcc-pa");
	if (IS_ERR(vcc_pa)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_pa);
		return ret;
	}

	vcc_qemmc = devm_regulator_get(&pdev->dev, "vcc-qemmc");
	if (IS_ERR(vcc_qemmc)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_qemmc);
		return ret;
	}

	vcc_pll = devm_regulator_get(&pdev->dev, "vcc-pll");
	if (IS_ERR(vcc_pll)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_pll);
		return ret;
	}

	vcc_ac = devm_regulator_get(&pdev->dev, "vcc-ac");
	if (IS_ERR(vcc_ac)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_ac);
		return ret;
	}

	vcc_ddrpll = devm_regulator_get(&pdev->dev, "vcc-ddrpll");
	if (IS_ERR(vcc_ddrpll)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_ddrpll);
		return ret;
	}

	vpp_ddr4 = devm_regulator_get(&pdev->dev, "vpp-ddr4");
	if (IS_ERR(vpp_ddr4)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vpp_ddr4);
		return ret;
	}

	vcc_lpddr = devm_regulator_get(&pdev->dev, "vcc-lpddr");
	if (IS_ERR(vcc_lpddr)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_lpddr);
		return ret;
	}

	vcc_camio = devm_regulator_get(&pdev->dev, "vcc-camio");
	if (IS_ERR(vcc_camio)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_camio);
		return ret;
	}

	vcc_amu = devm_regulator_get(&pdev->dev, "vcc-amu");
	if (IS_ERR(vcc_amu)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vcc_amu);
		return ret;
	}

	vdd_amu = devm_regulator_get(&pdev->dev, "vdd-amu");
	if (IS_ERR(vdd_amu)) {
		pr_err("%s: %d, error\n", __func__, __LINE__);
		ret = PTR_ERR(vdd_amu);
		return ret;
	}

	return 0;
}

static int regulator_test_remove(struct platform_device *pd)
{
	devm_regulator_put(vdd_cpu);
	devm_regulator_put(vdd_ax);
	devm_regulator_put(vcc_dram);
	devm_regulator_put(vdd_gpu);
	devm_regulator_put(vdd_sys);
	devm_regulator_put(vcc_io);
	devm_regulator_put(vcc_pa);
	devm_regulator_put(vcc_qemmc);
	devm_regulator_put(vcc_pll);
	devm_regulator_put(vcc_ac);
	devm_regulator_put(vcc_ddrpll);
	devm_regulator_put(vpp_ddr4);
	devm_regulator_put(vcc_lpddr);
	devm_regulator_put(vcc_camio);
	devm_regulator_put(vcc_amu);
	devm_regulator_put(vdd_amu);

	return 0;
}

static struct platform_driver regulator_test_driver = {
	.driver = {
		.name = "regulator_test",
		.owner = THIS_MODULE,
		.of_match_table = test_dt_ids,
	},
	.probe = regulator_test_probe,
	.remove = regulator_test_remove,
};

module_platform_driver(regulator_test_driver);
